<template>
  <div class="perf-container">
    <h1>Vue 性能优化指令: v-once 和 v-memo</h1>
    
    <!-- v-once 部分 -->
    <section class="section">
      <h2>v-once 指令</h2>
      <div class="description">
        <p>v-once 指令用于只渲染元素和组件<strong>一次</strong>。后续的更新将被跳过，元素/组件及其所有子节点将被视为静态内容。</p>
      </div>
      
      <div class="demo-box">
        <h3>v-once 演示</h3>
        
        <div class="controls">
          <button @click="count++">增加计数: {{ count }}</button>
          <button @click="updateTime">更新时间</button>
        </div>
        
        <div class="demo-content">
          <div class="demo-card">
            <h4>普通渲染 (会更新)</h4>
            <div class="result">
              <p>计数值: {{ count }}</p>
              <p>当前时间: {{ time }}</p>
            </div>
          </div>
          
          <div class="demo-card">
            <h4>使用 v-once (只渲染一次)</h4>
            <div class="result" v-once>
              <p>计数值: {{ count }}</p>
              <p>当前时间: {{ time }}</p>
            </div>
          </div>
        </div>
        
        <div class="code-block">
          <pre><code>
&lt;!-- 普通渲染 (会更新) --&gt;
&lt;div class="result"&gt;
  &lt;p&gt;计数值: {{ count }}&lt;/p&gt;
  &lt;p&gt;当前时间: {{ time }}&lt;/p&gt;
&lt;/div&gt;

&lt;!-- 使用 v-once (只渲染一次) --&gt;
&lt;div class="result" v-once&gt;
  &lt;p&gt;计数值: {{ count }}&lt;/p&gt;
  &lt;p&gt;当前时间: {{ time }}&lt;/p&gt;
&lt;/div&gt;
          </code></pre>
        </div>
      </div>
      
      <div class="info-box">
        <h3>v-once 适用场景</h3>
        <ul>
          <li>静态内容，如页面标题、版权信息</li>
          <li>只需要初始值的数据展示</li>
          <li>大型静态列表</li>
          <li>不需要响应式更新的组件</li>
        </ul>
      </div>
    </section>
    
    <!-- v-memo 部分 -->
    <section class="section">
      <h2>v-memo 指令</h2>
      <div class="description">
        <p>v-memo 指令接收一个依赖值数组，只有当数组中的值发生变化时，元素才会重新渲染。这可以用来有条件地跳过不必要的更新。</p>
      </div>
      
      <div class="demo-box">
        <h3>v-memo 基础演示</h3>
        
        <div class="controls">
          <button @click="valueA++">增加 A: {{ valueA }}</button>
          <button @click="valueB++">增加 B: {{ valueB }}</button>
          <button @click="valueC++">增加 C: {{ valueC }}</button>
        </div>
        
        <div class="demo-content">
          <div class="demo-card">
            <h4>普通渲染 (任何值变化都会更新)</h4>
            <div class="result">
              <p>A: {{ valueA }} | B: {{ valueB }} | C: {{ valueC }}</p>
              <p>渲染次数: {{ normalRenderCount }}</p>
            </div>
          </div>
          
          <div class="demo-card">
            <h4>使用 v-memo="[valueA, valueB]"</h4>
            <div 
              class="result" 
              v-memo="[valueA, valueB]"
              @vue:memo-updated="memoRenderCount++"
            >
              <p>A: {{ valueA }} | B: {{ valueB }} | C: {{ valueC }}</p>
              <p>渲染次数: {{ memoRenderCount }}</p>
              <p class="note">只有 A 或 B 变化时才会更新</p>
            </div>
          </div>
        </div>
        
        <div class="code-block">
          <pre><code>
&lt;!-- 普通渲染 (任何值变化都会更新) --&gt;
&lt;div class="result"&gt;
  &lt;p&gt;A: {{ valueA }} | B: {{ valueB }} | C: {{ valueC }}&lt;/p&gt;
  &lt;p&gt;渲染次数: {{ normalRenderCount }}&lt;/p&gt;
&lt;/div&gt;

&lt;!-- 使用 v-memo="[valueA, valueB]" --&gt;
&lt;div 
  class="result" 
  v-memo="[valueA, valueB]"
  @vue:memo-updated="memoRenderCount++"
&gt;
  &lt;p&gt;A: {{ valueA }} | B: {{ valueB }} | C: {{ valueC }}&lt;/p&gt;
  &lt;p&gt;渲染次数: {{ memoRenderCount }}&lt;/p&gt;
  &lt;p class="note"&gt;只有 A 或 B 变化时才会更新&lt;/p&gt;
&lt;/div&gt;
          </code></pre>
        </div>
      </div>
      
      <div class="demo-box">
        <h3>v-memo 与 v-for 结合使用</h3>
        
        <div class="controls">
          <button @click="addListItem">添加列表项</button>
          <button @click="updateRandomItem">更新随机项</button>
          <button @click="toggleFilter">{{ showEven ? '显示所有项' : '只显示偶数项' }}</button>
        </div>
        
        <div class="demo-content">
          <div class="list-container">
            <h4>普通列表渲染</h4>
            <ul class="item-list">
              <li v-for="item in displayList" :key="item.id" class="list-item">
                <span class="item-id">ID: {{ item.id }}</span>
                <span class="item-name">{{ item.text }}</span>
                <span class="item-renders">渲染次数: {{ item.renders }}</span>
              </li>
            </ul>
          </div>
          
          <div class="list-container">
            <h4>使用 v-memo 的列表渲染</h4>
            <ul class="item-list">
              <li 
                v-for="item in displayList" 
                :key="item.id" 
                v-memo="[item.text, showEven]"
                @vue:memo-updated="updateRenderCount(item.id)"
                class="list-item"
              >
                <span class="item-id">ID: {{ item.id }}</span>
                <span class="item-name">{{ item.text }}</span>
                <span class="item-renders">渲染次数: {{ item.memoRenders }}</span>
              </li>
            </ul>
          </div>
        </div>
        
        <div class="code-block">
          <pre>
            <code>
    <ul>
        <li v-for="item in displayList" :key="item.id" class="list-item" v-count-renders="'normal'">
            <span class="item-id">ID: {{ item.id }}</span>
            <span class="item-name">{{ item.text }}</span>
            <span class="item-renders">渲染次数: {{ item.normalRenders }}</span>
        </li>
        </ul>
 <h2>使用v-memo的列表</h2>
    <ul>
      <li 
        v-for="item in displayList" 
        :key="item.id" 
        v-memo="[item.text, showEven]"
        v-count-renders="'memo'"
        class="list-item"
      >
        <span class="item-id">ID: {{ item.id }}</span>
        <span class="item-name">{{ item.text }}</span>
        <span class="item-renders">渲染次数: {{ item.memoRenders }}</span>
      </li>
    </ul>
          </code>
        </pre>
        </div>
      </div>
      
      <div class="info-box">
        <h3>v-memo 适用场景</h3>
        <ul>
          <li>大型列表渲染优化</li>
          <li>只依赖特定状态的复杂组件</li>
          <li>需要精细控制更新条件的UI部分</li>
          <li>性能关键区域，如图表、动画等</li>
        </ul>
      </div>
    </section>
    
    <!-- 性能对比 -->
    <section class="section">
      <h2>性能优化指令对比</h2>
      <table class="comparison-table">
        <thead>
          <tr>
            <th>指令</th>
            <th>用途</th>
            <th>优点</th>
            <th>注意事项</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>v-once</td>
            <td>一次性渲染，永不更新</td>
            <td>最大化性能优化，完全跳过更新</td>
            <td>内容永远不会更新，使用时需谨慎</td>
          </tr>
          <tr>
            <td>v-memo</td>
            <td>有条件地跳过更新</td>
            <td>精细控制更新条件，按需渲染</td>
            <td>依赖数组需要正确设置</td>
          </tr>
        </tbody>
      </table>
    </section>
  </div>
</template>

<script>
import { ref, computed } from 'vue'

export default {
  name: 'PerformanceDirectives',
  setup() {
    // v-once 示例数据
    const count = ref(0)
    const time = ref(new Date().toLocaleTimeString())
    
    const updateTime = () => {
      time.value = new Date().toLocaleTimeString()
    }
    
    // v-memo 基础示例数据
    const valueA = ref(0)
    const valueB = ref(0)
    const valueC = ref(0)
    const normalRenderCount = ref(0)
    const memoRenderCount = ref(0)
    
    // 监听所有值的变化，更新普通渲染计数
    const watchValues = computed(() => {
      normalRenderCount.value++
      return [valueA.value, valueB.value, valueC.value]
    })
    
    // v-memo 与 v-for 结合示例数据
    const listItems = ref([
      { id: 1, text: '项目 1', renders: 0, memoRenders: 0 },
      { id: 2, text: '项目 2', renders: 0, memoRenders: 0 },
      { id: 3, text: '项目 3', renders: 0, memoRenders: 0 },
      { id: 4, text: '项目 4', renders: 0, memoRenders: 0 }
    ])
    const showEven = ref(false)
    
    // 过滤并更新渲染计数
    const displayList = computed(() => {
      // 更新普通渲染计数
      listItems.value.forEach(item => {
        item.renders++
      })
      
      // 根据过滤条件返回列表
      return showEven.value
        ? listItems.value.filter(item => item.id % 2 === 0)
        : listItems.value
    })
    
    // 添加新列表项
    const addListItem = () => {
      const newId = listItems.value.length + 1
      listItems.value.push({
        id: newId,
        text: `项目 ${newId}`,
        renders: 0,
        memoRenders: 0
      })
    }
    
    // 更新随机列表项
    const updateRandomItem = () => {
      if (listItems.value.length > 0) {
        const randomIndex = Math.floor(Math.random() * listItems.value.length)
        const item = listItems.value[randomIndex]
        item.text = `项目 ${item.id} (已更新 ${new Date().toLocaleTimeString()})`
      }
    }
    
    // 切换过滤条件
    const toggleFilter = () => {
      showEven.value = !showEven.value
    }
    
    // 更新 v-memo 渲染计数
    const updateRenderCount = (id) => {
      const item = listItems.value.find(item => item.id === id)
      if (item) {
        item.memoRenders++
      }
    }
    
    return {
      // v-once 示例
      count,
      time,
      updateTime,
      
      // v-memo 基础示例
      valueA,
      valueB,
      valueC,
      normalRenderCount,
      memoRenderCount,
      watchValues,
      
      // v-memo 与 v-for 结合示例
      listItems,
      displayList,
      showEven,
      addListItem,
      updateRandomItem,
      toggleFilter,
      updateRenderCount
    }
  }
}
</script>

<style scoped>
.perf-container {
  max-width: 1000px;
  margin: 0 auto;
  padding: 20px;
  font-family: 'Arial', sans-serif;
  color: #333;
}

h1 {
  text-align: center;
  color: #2c3e50;
  margin-bottom: 30px;
  border-bottom: 2px solid #3498db;
  padding-bottom: 10px;
}

.section {
  margin-bottom: 40px;
  background-color: #f8f9fa;
  border-radius: 8px;
  padding: 20px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

h2 {
  color: #3498db;
  margin-bottom: 15px;
}

h3 {
  color: #2c3e50;
  margin: 15px 0;
}

h4 {
  color: #3498db;
  margin-bottom: 10px;
}

.description {
  margin-bottom: 20px;
  line-height: 1.6;
}

.description p {
  margin-bottom: 10px;
}

.demo-box {
  background-color: white;
  border-radius: 6px;
  padding: 15px;
  margin-bottom: 20px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}

.controls {
  display: flex;
  gap: 10px;
  margin-bottom: 15px;
  flex-wrap: wrap;
}

button {
  background-color: #3498db;
  color: white;
  border: none;
  padding: 8px 15px;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.3s;
}

button:hover {
  background-color: #2980b9;
}

.demo-content {
  display: flex;
  gap: 20px;
  margin: 15px 0;
  flex-wrap: wrap;
}

.demo-card {
  flex: 1;
  min-width: 250px;
  background-color: #f1f5f9;
  padding: 15px;
  border-radius: 6px;
}

.result {
  padding: 10px;
  background-color: white;
  border-radius: 4px;
  border-left: 3px solid #3498db;
}

.note {
  font-size: 0.9em;
  color: #7f8c8d;
  font-style: italic;
  margin-top: 10px;
}

.code-block {
  background-color: #2c3e50;
  color: #ecf0f1;
  padding: 15px;
  border-radius: 5px;
  margin-top: 15px;
  overflow-x: auto;
}

pre {
  margin: 0;
  white-space: pre-wrap;
}

.info-box {
  background-color: #e8f4f8;
  padding: 15px;
  border-radius: 6px;
  margin-top: 20px;
}

.info-box ul {
  padding-left: 20px;
}

.info-box li {
  margin-bottom: 8px;
}

.list-container {
  flex: 1;
  min-width: 300px;
}

.item-list {
  list-style: none;
  padding: 0;
}

.list-item {
  display: flex;
  justify-content: space-between;
  padding: 10px;
  margin-bottom: 5px;
  background-color: white;
  border-radius: 4px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.1);
}

.item-id {
  font-weight: bold;
  color: #3498db;
}

.item-renders {
  color: #e74c3c;
}

.comparison-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 20px;
}

.comparison-table th, 
.comparison-table td {
  padding: 12px;
  text-align: left;
  border-bottom: 1px solid #ddd;
}

.comparison-table th {
  background-color: #3498db;
  color: white;
}

.comparison-table tr:nth-child(even) {
  background-color: #f2f2f2;
}
</style>